﻿using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Net;
using System.Threading;
using Urs.Data.Domain.Tasks;
using Urs.Core.Infrastructure;
using Urs.Data.Domain.Configuration;
using Urs.Services.Logging;

namespace Urs.Services.Tasks
{
    public partial class TaskThread : IDisposable
    {
        private static readonly string _scheduleTaskUrl;
        private Timer _timer;
        private bool _disposed;
        private readonly Dictionary<string, string> _tasks;
        static TaskThread()
        {
            var storeInformationSettings = EngineContext.Current.Resolve<StoreInformationSettings>();
            _scheduleTaskUrl = $"{storeInformationSettings.StoreUrl}scheduletask/runtask";
        }
        internal TaskThread()
        {
            this._tasks = new Dictionary<string, string>();
            this.Seconds = 10 * 60;
        }

        private void Run()
        {
            if (Seconds <= 0)
                return;

            this.StartedUtc = DateTime.Now;
             this.IsRunning = true;
            foreach (var taskType in _tasks.Values)
            {
                var postData = new NameValueCollection
                {
                    { "taskType", taskType }
                };

                try
                {
                    using (var client = new WebClient())
                    {

                        client.UploadValues(_scheduleTaskUrl, postData);
                    }
                }
                catch (Exception ex)
                {
                    var _serviceScopeFactory = EngineContext.Current.Resolve<IServiceScopeFactory>();

                    using (var scope = _serviceScopeFactory.CreateScope())
                    {
                        var logger = scope.ServiceProvider.GetRequiredService<ILogger>();
                        logger.Error(string.Format("{0}{1}-{2}", _scheduleTaskUrl, postData, ex.Message), ex);
                    }
                }
            }
            this.IsRunning = false;
        }

        private void TimerHandler(object state)
        {
            this._timer.Change(-1, -1);
            this.Run();
            if (this.RunOnlyOnce)
            {
                this.Dispose();
            }
            else
            {
                this._timer.Change(this.Interval, this.Interval);
            }
        }

        public void Dispose()
        {
            if ((this._timer != null) && !this._disposed)
            {
                lock (this)
                {
                    this._timer.Dispose();
                    this._timer = null;
                    this._disposed = true;
                }
            }
        }

        public void InitTimer()
        {
            if (this._timer == null)
            {
                this._timer = new Timer(TimerHandler, null, InitInterval, Interval);
            }
        }

        public void AddTask(ScheduleTask task)
        {
            if (!this._tasks.ContainsKey(task.Name))
            {
                this._tasks.Add(task.Name, task.Type);
            }
        }


        public int Seconds { get; set; }

        public int InitSeconds { get; set; }

        public DateTime StartedUtc { get; private set; }

        public bool IsRunning { get; private set; }

        public int Interval
        {
            get
            {
                var interval = Seconds * 1000;
                if (interval <= 0)
                    interval = int.MaxValue;
                return interval;
            }
        }

        public int InitInterval
        {
            get
            {
                var interval = InitSeconds * 1000;
                if (interval <= 0)
                    interval = 0;
                return interval;
            }
        }

        public bool RunOnlyOnce { get; set; }
    }
}
